#pragma once
#include <iostream>
#include <queue>
#include <cstring>
#include <pthread.h>
#include <unistd.h>
#include "cut.hpp"
using namespace std;
#define PTHREAD_T_NUM 5
template <class T>
class PthreadPool
{
public:
    PthreadPool()
    {
        pthread_mutex_init(&_mtx, nullptr);
        pthread_cond_init(&_empty, nullptr);
        pthread_cond_init(&_full, nullptr);
        Start();
    }
    void push(const T& val, Data<T>* ptr)
    {
        pthread_mutex_lock(&_mtx);
        while (_task.size() == PTHREAD_T_NUM)
        {
            pthread_cond_wait(&_full, &_mtx);
        }
        _task.emplace(val);
        _data.emplace(ptr);
        pthread_cond_signal(&_empty);
        pthread_mutex_unlock(&_mtx);
    }
    ~PthreadPool()
    {
        cout << " 析构" << endl;
        pthread_cond_destroy(&_empty);
        pthread_cond_destroy(&_full);
        pthread_mutex_destroy(&_mtx);
    }

private:
    void Start()
    {
        for (size_t i = 0; i < PTHREAD_T_NUM; i++)
        {
            Data<T>* ptr = new Data<T>;
            ptr->_ptr = this;
            pthread_create(_tid + i, nullptr, route, ptr);
        }
    }
    static void *route(void *args)
    {
        pthread_detach(pthread_self());
        Data<T> *ptr = reinterpret_cast<Data<T>*>(args);
        while (true)
        {

            T event;
            ptr->_ptr->pop(event, &ptr);
            // 先进行切割加序列化以及反序列化
            Cut tool(event);
            // 发送回客户端
            
            ptr->_eptr->Epoll_ctl(EPOLL_CTL_MOD,ptr->_fd, EPOLLIN | EPOLLOUT | EPOLLET);
            ptr->_outbuffer = event;
        }
        return nullptr;
    }
    void pop(T &val, Data<T>** data)
    {
        pthread_mutex_lock(&_mtx);
        while (_task.size() == 0)
        {
            pthread_cond_wait(&_empty, &_mtx);
        }
        val = _task.front();
        *data = _data.front();
        _task.pop();
        _data.pop();
        pthread_cond_signal(&_full);
        pthread_mutex_unlock(&_mtx);
    }

private:
    pthread_t _tid[PTHREAD_T_NUM];
    pthread_mutex_t _mtx;
    pthread_cond_t _empty;
    pthread_cond_t _full;
    queue<T> _task;
    queue<Data<T>*> _data;
};